package com.boge.study.arithmetic;

import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 输入一行字符，分别统计出其中英文字母、中文字符、空格、数字和其它字符的个数
 * 
 * 方法：可以根据各种字符在Unicode字符编码表中的区间来进行判断，如数字为'0'~'9'之间，英文字母为'a'~'z'或'A'~'Z'等，
 * Java判断一个字符串是否有中文是利用Unicode编码来判断，因为中文的编码区间为：0x4e00--0x9fbb， 但通用区间来判断中文也不非常精确，
 * 因为有些中文的标点符号利用区间判断会得到错误的结果。所以通过Character.UnicodeBlock来进行判断。
 * http://www.cnblogs.com/tianyaxue/p/3147471.html
 * @author Administrator
 *
 */
public class countCharacter {
	
	public static void main(String[] args) {
		
		Map<String, Integer> map = countCharacter("好的12 asa");
		for (String key : map.keySet()) {
			System.out.println(key + ":" + map.get(key));
		}
		
		System.out.println(getChineseNum3("2我的sas我的"));
		
	}
	
	public static Map<String, Integer> countCharacter(String str) {
		Map<String, Integer> countMap = new TreeMap<String, Integer>();
		
		int chCharacter = 0;
		int enCharacter = 0;
		int spaceCharacter = 0;
		int numberCharacter = 0;
		int otherCharacter = 0;
		
		for (int i = 0; i < str.length(); i++) {
			char temp = str.charAt(i);
			if (isChinese1(temp)) {
				chCharacter ++;
			} else if ((temp >= 'A' && temp <= 'Z') || (temp >= 'a' && temp <= 'z')) {
				enCharacter ++;
			} else if (temp == ' ') {
				spaceCharacter ++;
			} else if (temp >= '0' && temp <= '9') {
				numberCharacter ++;
			} else {
				otherCharacter ++;
			}
		}
		countMap.put("中文", chCharacter);
		countMap.put("英文", enCharacter);
		countMap.put("空格", spaceCharacter);
		countMap.put("数字", numberCharacter);
		countMap.put("其他", otherCharacter);
		
		return countMap;
		
	}
	
	/**
	 * 判断字符是否是中文
	 * 方法：根据一个中文占两个字节，假如一个字符的字节数大于8，则判断为中文
	 * Integer.toBinaryString方法，就是将输入的数字转换成二进制数，但是转换输出的是String类型的字符串
	 * @param ch
	 * @return
	 */
	private static boolean isChinese1(char ch) {
		String len = Integer.toBinaryString(ch);
		if (len.length() > 8) {
			return true;
		}
		return false;
	}
	
	/**
	 * 获取字符串中中文字符的个数
	 * 方法:[\u4e00-\u9fa5]是中文的Unicode编码范围，用正则表达式的方法，若字符串中有字符满足中文的正则表达式，
	 * 则判定为中文，将其替换为两个字符，故长度差就为中文的个数。
	 * @param str
	 * @return
	 */
	private static int getChineseNum1(String str) {
		String regEx = "[\\u4e00-\\u9fa5]";
        String term = str.replaceAll(regEx, "aa");
        int count = term.length()-str.length();
        return count;
	}
	
	/**
	 * 获取字符串中中文字符的个数
	 * 方法：用了Pattern类，若Matcher可以匹配，则说明找到了一个中文字符。
	 * @param str
	 * @return
	 */
	private static int getChineseNum2(String str) {
		String regEx = "[\\u4e00-\\u9fa5]";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        int count = 0;
        while (m.find()) {
			count ++;
		}
        return count;
	}
	
	/**
	 * 获取字符串中中文字符的个数
	 * 方法：仍然是正则表达式的判断方法。该正则表达式的含义是出去中文以外的所有字符的Unicode编码，
	 * 将这些除去中文字符之外的其他字符去除，剩下的就都是中文字符，得到的就是中文字符串的数据。
	 * @param str
	 * @return
	 */
	private static int getChineseNum3(String str) {
		int count = 0;
		String regex = "[^\u4e00-\u9fa5]+";
		String[] term = str.split(regex);
		for (int i = 0; i < term.length; i++) {
			System.out.println("term[i]:" + term[i]);
			if (term[i].length() > 0) { //第一和最后一个字符可能是空（无）
				count = count + term[i].length();
			}
		}
		return count;
		
	}
	
	/**
	 * 获取字符串中中文字符的个数
	 * 方法：通过字节判断
	 * @param str
	 * @return
	 */
	private static int getChineseNum4(String str) {
		int count = 0;
		byte[] buf = str.getBytes();
		for (int i = 0; i < buf.length; i++) {
			if (buf[i] < 0) { //中文字符byte值为负数
				count ++;
				i ++;//中文字符两个字节
			}
		}
		return count;
	}
	
}
